#pragma once
#include "li_collections.h"
#include "hashlib.h"
#include "li_pipe.h"
#include "li_list.h"
#include "li_vm.h"
#include "li_vars.h"
#include "RPE.h"
typedef int (*_SysIns)(Li_CB, Any);

#define __sys_throw(exception) \
	{                          \
		cb->erMsg = exception; \
		return -__LINE__;      \
	}

#define __sys_assert(exp)                \
	{                                    \
		if (!(exp))                      \
			__sys_throw("assert failed") \
	}

#pragma region stack frame operation
int __sys_init_stack(Li_SF sf)
{
	sf->pageSize = sizeof(Li_SF_t);
	sf->lr = NULL;
	sf->ls = NULL;
	sf->locals.cmds = NULL;
	sf->locals.vars = NULL;
	sf->locals.funs = NULL;
	return 0;
}
int __sys_push_stack(Li_CB cb, Li_Ins next_pc)
{
	Li_SF sf = cb->sp;
	// to next page
	cb->sp = (Li_SF)((uint8_t *)sf + sf->pageSize);
	// init new page
	cb->sp->pageSize = sizeof(Li_SF_t);
	cb->sp->lr = cb->pc;
	cb->sp->ls = sf;
	// jump
	cb->pc = next_pc;
	return 0;
}
int __sys_push_stack2(Li_CB cb)
{
	Li_SF sf = cb->sp;
	// to next page
	cb->sp = (Li_SF)((uint8_t *)sf + sf->pageSize);
	// init new page
	cb->sp->pageSize = sizeof(Li_SF_t);
	cb->sp->lr = cb->pc;
	cb->sp->ls = sf;
	cb->sp->locals.cmds = NULL;
	cb->sp->locals.vars = NULL;
	cb->sp->locals.funs = NULL;
	return 0;
}
int __sys_pop_stack(Li_CB cb)
{
	Li_SF sf = cb->sp;
	// clear this page
	if (sf->locals.vars)
	{
		delete_list(sf->locals.vars);
	}
	if (sf->locals.funs)
	{
		delete_list(sf->locals.funs);
	}
	// to last page
	cb->sp = sf->ls;
	cb->pc = cb->sp->lr;
	return 0;
}
int __sys_pop_stack2(Li_CB cb)
{
	Li_SF sf = cb->sp;
	// TODO: clean vars, funs...
	// to last page
	cb->sp = sf->ls;
	return 0;
}

#define StackAlloc(T) (__sys_stack_alloc(cb, sizeof(T)))
#define StackGet(T) ((T *)__sys_stack_get(cb, sizeof(T)))
void *__sys_stack_alloc(Li_CB cb, int size)
{
	if (size & (sizeof(int) - 1))
	{
		size &= (~(sizeof(int) - 1));
		size += sizeof(int);
	}
	void *top = ((uint8_t *)(cb->sp)) + cb->sp->pageSize;
	cb->sp->pageSize += size;
	return top;
}
void *__sys_stack_get(Li_CB cb, int size)
{
	if (size & (sizeof(int) - 1))
	{
		size &= (~(sizeof(int) - 1));
		size += sizeof(int);
	}
	cb->sp->pageSize -= size;
	void *top = ((uint8_t *)(cb->sp)) + cb->sp->pageSize;
	return top;
}
void *__sys_stack_get2(Li_SF sf, int size)
{
	if (size & (sizeof(int) - 1))
	{
		size &= (~(sizeof(int) - 1));
		size += sizeof(int);
	}
	sf->pageSize -= size;
	void *top = ((uint8_t *)(sf)) + sf->pageSize;
	return top;
}

static Var __find_var(Li_CB cb, HASH hs)
{
	Li_SF sf = cb->sp;
	Li_List vars = sf->locals.vars;
	int index = -1;
	if (vars)
		index = searchObj3_t(vars, hs);
	while (index < 0)
	{
		sf = sf->ls;
		if (!sf)
		{
			return NULL;
		}
		vars = sf->locals.vars;
		if (vars)
			index = searchObj3_t(vars, hs);
	}
	Var var = list_content(vars, Var_t) + index;
	return var;
}
static Fun __find_fun(Li_CB cb, HASH hs)
{
	Li_SF sf = cb->sp;
	Li_List funs = sf->locals.funs;
	int index = -1;
	if (funs)
		index = searchObj3_t(funs, hs);
	while (index < 0)
	{
		sf = sf->ls;
		if (!sf)
		{
			return NULL;
		}
		funs = sf->locals.funs;
		if (funs)
			index = searchObj3_t(funs, hs);
	}
	Fun fun = list_content(funs, Fun_t) + index;
	return fun;
}

#pragma endregion

#pragma region built - in instructions

/* instruction annotation format:

CmdType arg0 arg1
'*'  -> register
'[]' -> args

|---------------|---------------------------------------------------|-----------------------------------------------------------|
|	CodeName	|						Usage						|						What to do							|
|---------------|---------------------------------------------------|-----------------------------------------------------------|
|ans			|	ANS (val:Val_t)									|	display a calculation result							|
|cal			|	CAL [n:int] [items:REPItem_t]... ->(res:Val_t)	|	calculate a RPE											|
|if 			|	if [offset:int] ([value:Val_t])					|	if value is True then goto								|
|if-not			|	if_not [offset:int] ([value:Val_t])				|	if value is False then goto								|
|goto			|	goto [offset:int]								|	set *pc													|
|end			|	end												|	reset *pc												|
|set			|	set [name:str] [hs:HASH] (val:Val_t)			|	assign a var from VARS, create one if not exist			|
|setu			|	setu [name:str] [hs:HASH]						|	assign a var with null value							|
|ldrrv			|	LDRRV [varName] [hashCode] ->(value:Val_t)		|	load a var(Val_t) from VARS to a relative position		|
|index			|	INDEX [varName] [hashCode] ->(var_ref:Val)		|	ref a var(Val) from VARS to a relative position			|
|cs				|	cs [size:int]									|	clean stack												|
|continue		|	continue										|	continue												|
|break			|	break											|	break													|
|reg			|	reg [offset1:int] [offset2:int]					|	push a SF, register entry and exit						|
|regn			|	regn [offset1:int] [offset2:int] (n:Val_t)		|	push a SF, register entry, exit and loop_count			|
|*for			|	for ^(i:Val) ^(b:Val_t) ^(c:Val_t)				|	determine a for block									|
|*loop			|	loop											|	jump to exit if loop_count<0

|---------------|---------------------------------------------------|-----------------------------------------------------------|
|*cmd			|	cmd entry:Any, argn:int, argv:str...			|	run a cmd given args									|
|*add			|	ADD a:Val, b:Val_t								|	add a var with a number/value							|
|*if-greater	|	if_greater offset:int							|	if *rtc>=0 goto											|
|*if-lessen		|	if_lessen offset:int							|	if *rtc<=0 goto											|
|*call			|	--------------------							|	call a function #TODO									|
|*return		|	--------------------							|	return form a function #TODO							|
|ldr			|	load a int-type var form VARS to a given position		|	ldr name:str, hs:HASH, dst:int
|ldrf			|	load a float-type var form VARS to a given position		|
|ldrr			|	ldrr name:str, hs:HASH, offset:int				|	load a int-type var from VARS to a relative position	|
|ldrfr			|	ldrfr name:str, hs:HASH, offset:int				|	load a float-type var from VARS to a relative position	|

*/

#define Arg0(type) (*((type *)args))
#define Arg(i, type) (((type *)args)[i])
#define Argi(i, type) type arg##i = (((type *)args)[i])
#define _ShiftArg(v) (uint8_t *)args += sizeof(v)
#define ShiftArg(type) \
	*(type *)args;     \
	_ShiftArg(type)

#include <stdio.h>

static int __sys_ans(Li_CB cb, Any args) // ans (val:Val_t)
{
	Val res = StackGet(Val_t);
	if (res->type & VarTypeFloat)
	{
		printf("ans=%f\n", res->val.vf);
	}
	else if (res->type & VarTypeInt)
	{
		printf("ans=%d\n", res->val.vi);
	}
	else if (res->type & VarTypeBool)
	{
		printf("ans=%s\n", res->val.vi ? "true" : "false");
	}
	else if (res->type & VartypeStr)
	{
		printf("ans=%s\n", res->val.vs);
	}
	else
	{
		printf("ans=<Val_t>\n");
	}
	return 0;
}
static int __sys_cal(Li_CB cb, Any args) // CAL [n:int] [RPEItem_t:REPItem_t]... ->(res:Val_t)
{
	int n = Arg0(uint32_t);
	(uint8_t *)args += sizeof(uint32_t);
	int8_t *items = (int8_t *)args;
	RPEVal_t res;
	int ok = RPE_execute_from_compact(n, items, __find_var, __find_fun, cb, &res, ((uint8_t *)(cb->sp) + cb->sp->pageSize), cb->txt);
	if (ok < 0)
	{
#define Case(x)          \
	case x:              \
		__sys_throw(#x); \
		break;
		switch (ok)
		{
			Case(RPEE_empty_input);
			Case(RPEE_invalid_expression);
			Case(RPEE_unexpected_error);
			Case(RPEE_variable_not_found);
		default:
			__sys_throw("syntax error in expression");
			break;
		}
#undef Case
	}
	RPEVal p = __sys_stack_alloc(cb, sizeof(RPEVal_t));
	*p = res;
	return 0;
}

static int __sys_reg(Li_CB cb, Any args) // reg [startOffset:int] [endPosition:int]
{
	__sys_push_stack2(cb);
	cb->sp->entry = cb->pc + ShiftArg(int32_t); // for entry, absolute position
	cb->sp->lr = cb->pc + Arg0(int32_t);		// for exit, absolute position
	return 0;
}
static int __sys_regn(Li_CB cb, Any args) // regn [startOffset:int] [endPosition:int] (loopCount:Val_t)
{
	Val val = StackGet(Val_t);
	int loop_count = 0;
	// set *loop_count
	if (val->type & (VartypeStr | VarTypeArray))
	{
		__sys_throw("bad type");
	}
	if (_IS(val, Float))
	{
		loop_count = val->val.vf;
	}
	else if (_IS(val, Int))
	{
		loop_count = val->val.vi;
	}
	loop_count++;
	if (loop_count <= 0)
	{
		__sys_throw("bad arg, loop time muster be greater than zero");
	}
	__sys_push_stack2(cb);
	cb->sp->entry = cb->pc + ShiftArg(int32_t); // for entry, absolute position
	cb->sp->lr = cb->pc + Arg0(int32_t);		// for exit, absolute position
	cb->sp->loop_count = loop_count;

	return 0;
}
static int __sys_loop(Li_CB cb, Any args) // loop
{
	if (!--(cb->sp->loop_count))
	{
		cb->pc = cb->sp->lr;
		__sys_pop_stack2(cb);
		return 0;
	}
	return 0;
}

static int __sys_frt(Li_CB cb, Any args) // frt ^(i:Val) ^(b:Val_t) ^(c:Val_t)
{
	Li_SF sf = cb->sp->ls;
	int page_size = sf->pageSize; // backup
	Val c = ((Val_t *)__sys_stack_get2(sf, sizeof(Val_t)));
	Val b = ((Val_t *)__sys_stack_get2(sf, sizeof(Val_t)));
	Val i = *((Val *)__sys_stack_get2(sf, sizeof(Val)));
	sf->pageSize = page_size;

	int dir_ascend = 1;
	int itype = 0;
	if (_IS(i, Int))
	{
		itype = 1;
	}
	else if (!_IS(i, Float))
	{
		__sys_throw("bad type");
	}
	if (_IS(b, Float))
	{
		if (b->val.vf < 0)
			dir_ascend = 0;
		else if (b->val.vf == 0)
		{
			__sys_throw("step is 0");
		}
	}
	else if (_IS(b, Int))
	{
		if (b->val.vi < 0)
			dir_ascend = 0;
		else if (b->val.vi == 0)
		{
			__sys_throw("step is 0");
		}
	}
	else
	{
		__sys_throw("bad type");
	}
	if (!(c->type & (VarTypeInt | VarTypeFloat)))
	{
		__sys_throw("bad type");
	}
	if (dir_ascend)
	{
		if (!itype)
		{
			if (i->val.vf >= _VAL(c))
			{
				cb->pc = cb->sp->lr;
				__sys_pop_stack2(cb);
				return 0;
			}
		}
		else
		{
			if (i->val.vi >= _VAL(c))
			{
				cb->pc = cb->sp->lr;
				__sys_pop_stack2(cb);
				return 0;
			}
		}
	}
	else
	{
		if (!itype)
		{
			if (i->val.vf <= _VAL(c))
			{
				cb->pc = cb->sp->lr;
				__sys_pop_stack2(cb);
				return 0;
			}
		}
		else
		{
			if (i->val.vi <= _VAL(c))
			{
				cb->pc = cb->sp->lr;
				__sys_pop_stack2(cb);
				return 0;
			}
		}
	}
	return 0;
}
static int __sys_for(Li_CB cb, Any args) // for ^(i:Val) ^(b:Val_t) ^(c:Val_t)
{
	Li_SF sf = cb->sp->ls;
	int page_size = sf->pageSize; // backup
	Val c = ((Val_t *)__sys_stack_get2(sf, sizeof(Val_t)));
	Val b = ((Val_t *)__sys_stack_get2(sf, sizeof(Val_t)));
	Val i = *((Val *)__sys_stack_get2(sf, sizeof(Val)));
	sf->pageSize = page_size;

	int dir_ascend = 1;
	int itype = 0;
	if (_IS(i, Float))
	{
		i->val.vf += _VAL(i);
		// i->val.vf += _IS(b, Float) ? b->val.vf : b->val.vi;
	}
	else if (_IS(i, Int))
	{
		itype = 1;
		i->val.vi += _VAL(b);
		// i->val.vi += _IS(b, Float) ? b->val.vf : b->val.vi;
	}
	else
	{
		__sys_throw("bad type");
	}
	if (_IS(b, Float))
	{
		if (b->val.vf < 0)
			dir_ascend = 0;
		else if (b->val.vf == 0)
		{
			__sys_throw("step is 0");
		}
	}
	else if (_IS(b, Int))
	{
		if (b->val.vi < 0)
			dir_ascend = 0;
		else if (b->val.vi == 0)
		{
			__sys_throw("step is 0");
		}
	}
	else
	{
		__sys_throw("bad type");
	}
	if (!(c->type & (VarTypeInt | VarTypeFloat)))
	{
		__sys_throw("bad type");
	}
	if (dir_ascend)
	{
		if (!itype)
		{
			if (i->val.vf >= _VAL(c)) //(_IS(c, Float) ? c->val.vf : c->val.vi)
			{
				cb->pc = cb->sp->lr;
				__sys_pop_stack2(cb);
				return 0;
			}
		}
		else
		{
			if (i->val.vi >= _VAL(c))
			{
				cb->pc = cb->sp->lr;
				__sys_pop_stack2(cb);
				return 0;
			}
		}
	}
	else
	{
		if (!itype)
		{
			if (i->val.vf <= _VAL(c))
			{
				cb->pc = cb->sp->lr;
				__sys_pop_stack2(cb);
				return 0;
			}
		}
		else
		{
			if (i->val.vi <= _VAL(c))
			{
				cb->pc = cb->sp->lr;
				__sys_pop_stack2(cb);
				return 0;
			}
		}
	}
	return 0;
}
static int __sys_continue(Li_CB cb, Any args)
{
	cb->pc = cb->sp->entry;
	return 0;
}
static int __sys_break(Li_CB cb, Any args)
{
	cb->pc = cb->sp->lr;
	__sys_pop_stack2(cb);
	return 0;
}

static int __sys_if(Li_CB cb, Any args) // if (value:Val_t) [offset:int]
{
	Val res = StackGet(Val_t);
	if (res->type & VarTypeFloat)
	{
		if (res->val.vf)
		{
			cb->pc += Arg0(int32_t);
			return 0;
		}
	}
	else if (res->type & (VarTypeInt | VarTypeBool))
	{
		if (res->val.vi)
		{
			cb->pc += Arg0(int32_t);
			return 0;
		}
	}
	else if (res->type & VartypeStr)
	{
		if (res->val.vs && *(res->val.vs))
		{
			cb->pc += Arg0(int32_t);
			return 0;
		}
	}
	else
	{
		__sys_throw("bad type");
	}
	return 0;
}
static int __sys_if_not(Li_CB cb, Any args) // if [exp] goto [i]
{
	Val res = StackGet(Val_t);
	if (res->type & VarTypeFloat)
	{
		if (!(res->val.vf))
		{
			cb->pc += Arg0(int32_t);
			return 0;
		}
	}
	else if (res->type & (VarTypeInt | VarTypeBool))
	{
		if (!(res->val.vi))
		{
			cb->pc += Arg0(int32_t);
			return 0;
		}
	}
	else if (res->type & VartypeStr)
	{
		if (!(res->val.vs) || !(*(res->val.vs)))
		{
			cb->pc += Arg0(int32_t);
			return 0;
		}
	}
	else
	{
		__sys_throw("bad type");
	}
	return 0;
}

static int __sys_cmd(Li_CB cb, Any args) // CMD [amd_address] [argn] [argv]
{
	typedef int32_t (*_Cmd_def)(int32_t, char **);
	cb->rtc = Arg0(_Cmd_def)(Arg(1, int32_t), &Arg(2, char *));
	return 0;
}
static int __sys_goto(Li_CB cb, Any args) // goto [i]
{
	int ind = *(int32_t *)args;
	cb->pc += ind;
	return 0;
}

static int __sys_set(Li_CB cb, Any args) // set [name:str], [hs:HASH], (val:Val_t)
{
	int32_t ind = ShiftArg(int32_t);
	str name = cb->txt + ind;
	HASH hs = ShiftArg(HASH);
	Val val = StackGet(Val_t);
	Li_List vars = cb->sp->locals.vars;
	if (!vars)
	{
		cb->sp->locals.vars = new_li(Var_t);
		vars = cb->sp->locals.vars;
		goto create_new_var;
	}
	ind = searchObj2_t(vars, name, hs);
	if (ind < 0)
	{
	create_new_var:
		Var_t new_var = {.name = name, .val_t = *val};
		addToVar(vars, &new_var);
		return 0;
	}
	// #TODO: free var
	list_content(vars, Var_t)[ind].val_t = *val;
	return 0;
}
static int __sys_setu(Li_CB cb, Any args) // setu [name:str], [hs:HASH]
{
	int32_t ind = ShiftArg(int32_t);
	str name = cb->txt + ind;
	HASH hs = ShiftArg(HASH);
	Li_List vars = cb->sp->locals.vars;
	if (!vars)
	{
		cb->sp->locals.vars = new_li(Var_t);
		vars = cb->sp->locals.vars;
	}
	ind = searchObj2_t(vars, name, hs);
	if (ind >= 0)
	{
		return 0;
	}
	Var_t new_var = {.name = name, .val_t = {.type = 0, .len = 0}};
	addToVar(vars, &new_var);
	return 0;
}
static int __sys_ldr(Li_CB cb, Any args) // LDR [varName] [hashCode] ->(value:Val_t)
{
	const char *name = cb->txt + Arg0(int32_t);
	Argi(1, uint32_t);
	// Argi(2, int32_t);
	// Li_SF sf = cb->sp;
	// Li_List vars = sf->locals.vars;
	// int index;
	// index = searchObj2_t(vars, name, arg1);
	// while (index < 0)
	// {
	// 	sf = sf->ls;
	// 	if (!sf)
	// 	{
	// 		__sys_throw("var not found");
	// 	}
	// 	vars = sf->locals.vars;
	// 	index = searchObj2_t(vars, name, arg1);
	// }
	// Var var = list_content(vars, Var_t) + index;
	Var var = __find_var(cb, arg1);
	if (!var)
	{
		__sys_throw("var not found");
	}
	// int32_t *now = ((int32_t *)args) + 2;
	Val dst = StackAlloc(Val_t);
	// Val_t *dst = (Val_t *)(now + arg2);
	*dst = var->val_t;
	return 0;
}
static int __sys_index(Li_CB cb, Any args) // INDEX [varName] [hashCode] ->(var_ref:Val)
{
	const char *name = cb->txt + Arg0(int32_t);
	Argi(1, uint32_t);
	// Argi(2, int32_t);
	// Li_SF sf = cb->sp;
	// Li_List vars = sf->locals.vars;
	// int index;
	// index = searchObj2_t(vars, name, arg1);
	// while (index < 0)
	// {
	// 	sf = sf->ls;
	// 	if (!sf)
	// 	{
	// 		__sys_throw("var not found");
	// 	}
	// 	vars = sf->locals.vars;
	// 	index = searchObj2_t(vars, name, arg1);
	// }
	// Var var = list_content(vars, Var_t) + index;
	Var var = __find_var(cb, arg1);
	if (!var)
	{
		__sys_throw("var not found");
	}
	// int32_t *now = ((int32_t *)args) + 2;
	Val *dst = StackAlloc(Val);
	// Val *dst = (Val *)(now + arg2);
	*dst = &(var->val_t);
	return 0;
}
static int __sys_end(Li_CB cb, Any args)
{
	cb->pc = NULL;
	cb->pc--;
	return 0;
}
static int __sys_cs(Li_CB cb, Any args) // cs [size:int]
{
	cb->sp->pageSize -= Arg0(int32_t);
	return 0;
}

#pragma region not used
static int __sys_add(Li_CB cb, Any args) // ADD [a:Val] [b:Val_t]
{
	Argi(0, Val_t *);
	(uint8_t *)args += sizeof(arg0);
	Val_t *arg1 = (Val_t *)args;
	if ((arg0->type | arg1->type) & (VarTypeArray))
	{
		__sys_throw("type error");
	}
	if ((arg0->type | arg1->type) & VarTypeFloat)
	{
		arg0->type = VarTypeFloat;
#define VAL(i) (arg##i->type & VarTypeFloat ? arg##i->val.vf : arg##i->val.vi)
		arg0->val.vf = VAL(0) + VAL(1);
#undef VAL
	}
	else if ((arg0->type | arg1->type) & VartypeStr)
	{
		if (!(arg1->type & VartypeStr))
		{
			__sys_throw("type error");
		}
		// TODO: String cat
	}
	else
	{
		arg0->type = VarTypeInt;
		arg0->val.vi = arg0->val.vi + arg1->val.vi;
	}
	return 0;
}
static int __sys_if_greater(Li_CB cb, Any args) // if [exp]>=0 goto [i]
{
	if (cb->rtc >= 0)
	{
		cb->pc += Arg0(int32_t);
	}
	return 0;
}
static int __sys_if_lessen(Li_CB cb, Any args) // if *rtc<=0 goto [i]
{
	if (cb->rtc <= 0)
	{
		cb->pc += Arg0(int32_t);
	}
	return 0;
}
static int __sys_call(Li_CB cb, Any args) // call [NextPc] [argn] [argv]
{
	// TODO: call function
	cb->sp++;
	Li_SF sp = cb->sp;
	sp->lr = cb->pc;
	sp->argn = Arg(1, uint32_t);
	sp->argv = Arg(2, Any);
	// sp->locals =
	return 0;
}
static int __sys_return(Li_CB cb, Any args)
{
	Li_SF sp = cb->sp;
	// cb->argn = sp->argn;
	// cb->argv = sp->argv;
	// cb->locals = sp->locals;
	cb->pc = sp->lr;
	cb->sp--;
	return 0;
}

#pragma endregion
#pragma endregion

#define S(x) __sys_##x
const _SysIns __ISC[] = {
	__SYSINS__};
#undef S

int _run_instruction(Li_CB cb, Any args_array[])
{
	return __ISC[cb->pc->ins](cb, args_array + cb->pc++->args);
}
int _run_instruction_all(Li_CB cb, Any args_array[])
{
	int rtc = 0;
	while (cb->pc)
	{
		rtc = __ISC[cb->pc->ins](cb, args_array + cb->pc->args);
		if (rtc)
		{
			return rtc;
		}
		cb->pc++;
	}
	return rtc;
}
int run_from_bytes_block(int *codes, Li_CB cb)
{
	int total_size = *codes;
	int8_t *_p = codes + 4;
	cb->pc = _p;
	_p += codes[1];
	int *args_heap = _p;
	_p += codes[2];
	cb->txt = _p;
	return _run_instruction_all(cb, args_heap);
}
// @deprecated
int disassemble(Li_List _ins, Li_List _args)
{
	Li_Ins ins = list_content(_ins, Li_Ins_t);
	int *args = list_content(_args, int);
	Li_List _txt = (Li_List)(args[0]);
	str txt = list_content(_txt, char);
	int txt_size = _txt->count;

	for (int i = 0; i < _ins->count; i++)
	{
		printf("%d\t", i);
#define S(x, kn)                              \
	case _##x:                                \
		printf("%s:%d\t\t", #x, ins[i].args); \
		for (int j = 0; j < kn; j++)          \
		{                                     \
			if (!ins[i].args)                 \
				break;                        \
			int p = args[ins[i].args + j];    \
			printf("%08x, ", p);              \
		}                                     \
		printf("\n");                         \
		break;

		switch (ins[i].ins)
		{
		case _cal:
			printf("%s:%d\t\t", "cal", ins[i].args);
			int from = ins[i].args;
			int n = args[from++];
			printf("%d, [", n);
			RPEItem bs = args + from;
			for (int j = 0; j < n; j++, bs++)
			{
				if (bs->type == RPETypeImmediateNumber)
				{
					if (bs->val.type & VarTypeInt)
					{
						printf("%d, ", bs->val.val.vi);
					}
					else if (bs->val.type & VarTypeFloat)
					{
						printf("%f, ", bs->val.val.vf);
					}
					else
						printf("<Number>, ");
				}
				else if (bs->type == RPETypeVar)
				{
					printf("<Var>, ");
				}
				else if (bs->type == RPETypeOperator)
				{
					printf("<Operator>, ");
				}
				else if (bs->type == RPETypeFunction)
				{
					printf("<Function>, ");
				}
			}
			printf("]\n");
			break;
		case _index:
			printf("%s:%d\t\t", "index", ins[i].args);
			from = ins[i].args;
			int ind = args[from++];
			printf("'%s', ", txt + ind);
			printf("%08x, ", args[from++]);
			printf("\n");
			break;
		case _set:
			printf("%s:%d\t\t", "set", ins[i].args);
			from = ins[i].args;
			ind = args[from++];
			printf("'%s', ", txt + ind);
			printf("%08x, ", args[from++]);
			printf("\n");
			break;
		case _setu:
			printf("%s:%d\t\t", "setu", ins[i].args);
			from = ins[i].args;
			ind = args[from++];
			printf("'%s', ", txt + ind);
			printf("%08x, ", args[from++]);
			printf("\n");
			break;
		case _reg:
			printf("%s:%d\t\t", "reg", ins[i].args);
			from = ins[i].args;
			printf("%d, ", args[from++]);
			printf("%d, ", args[from++]);
			printf("\n");
			break;
		case _regn:
			printf("%s:%d\t\t", "regn", ins[i].args);
			from = ins[i].args;
			printf("%d, ", args[from++]);
			printf("%d, ", args[from++]);
			printf("\n");
			break;
			S(frt, 1);
			S(ans, 0);
			// S(reg, 2);
			// S(regn, 2);
			S(for,0);
			// S(add, 0); //*
			S(continue, 0);
			S(break, 0);
			// S(cal, 4);
			S(if, 1);
			S(if_not, 1);
			// S(if_greater, 0);
			S(loop, 3);
			// S(loop_return, 0);
			S(cmd, 3);
			S(goto, 1);
			// S(set, 5);
			// S(ldr, 3);
			// S(ldrr, 3);
			// S(ldrf, 3);
			// S(ldrfr, 3);
			// S(ldrrv, 3);
			// S(index, 3);
			S(call, 0);
			S(return, 0);
			S(end, 0);
			S(cs, 0);
		default:
			break;
		}
#undef S
	}
	return 0;
}
int disassemble_from_bytes_block(int *codes)
{
	int total_size = *codes;
	int8_t *_p = codes + 4;
	Li_Ins ins = _p;
	_p += codes[1];
	int *args = _p;
	_p += codes[2];
	char *txt = _p;
	int n = codes[1] / 4;
	printf("[total size:%d bytes]\n", codes[0]);
	printf("[code size:%d bytes]\n", codes[1]);
	printf("[arg size:%d bytes]\n", codes[2]);
	printf("[txt size:%d bytes]\n", codes[3]);

	for (int i = 0; i < n; i++)
	{
		printf("%d\t", i);
#define S(x, kn)                              \
	case _##x:                                \
		printf("%s:%d\t\t", #x, ins[i].args); \
		for (int j = 0; j < kn; j++)          \
		{                                     \
			if (!ins[i].args)                 \
				break;                        \
			int p = args[ins[i].args + j];    \
			printf("%08x, ", p);              \
		}                                     \
		printf("\n");                         \
		break;

		switch (ins[i].ins)
		{
		case _cal:
			printf("%s:%d\t\t", "cal", ins[i].args);
			int from = ins[i].args;
			int n = args[from++];
			printf("%d, [", n);
			// RPEItem bs = args + from;
			char *ts = args + from;
			int m = n & (sizeof(Any) - 1) ? ((n & ~(sizeof(Any) - 1)) + sizeof(Any)) : n;
			int32_t *data = ts + m;
			for (int j = 0; j < n; j++)
			{
				int ope_type = (ts[j]) & 0x70;
				if (ope_type == RPECEmpty)
				{
					continue;
				}
				if (ope_type == RPECNumber) // instant number
				{
					int type = (ts[j] & 0xf) | VarTypeReadOnly;
					CVal cv = *(CVal *)data++;
					if (type & VarTypeInt)
					{
						printf("%d,", cv);
					}
					else if (type & VarTypeFloat)
					{
						printf("%g,", cv);
					}
					else if (type & VarTypeBool)
					{
						printf("%s,", cv.vi ? "True" : "False");
					}
					else if (type & VartypeStr)
					{
						printf("'%s',", cv.vi + txt);
					}
					else
					{
						printf("<Val_t>,");
					}
					continue;
				}
				if (ope_type == RPECVar) // var
				{
					printf("<Var, hs=%d>,", *(HASH *)data++);
					continue;
				}
				if (ope_type == RPECOperator)
				{
					Any f = *data++;
					const str oper = _RPE_operator_to_str(f);
					printf("%s,", oper);
					continue;
				}

				if (ope_type == RPECFun)
				{
					printf("<Fun, hs=%d>,", *(HASH *)data++);
					continue;
				}
			}
			printf("]\n");
			break;
		case _index:
			printf("%s:%d\t\t", "index", ins[i].args);
			from = ins[i].args;
			int ind = args[from++];
			printf("'%s', ", txt + ind);
			printf("%08x, ", args[from++]);
			printf("\n");
			break;
		case _set:
			printf("%s:%d\t\t", "set", ins[i].args);
			from = ins[i].args;
			ind = args[from++];
			printf("'%s', ", txt + ind);
			printf("%08x, ", args[from++]);
			printf("\n");
			break;
		case _setu:
			printf("%s:%d\t\t", "setu", ins[i].args);
			from = ins[i].args;
			ind = args[from++];
			printf("'%s', ", txt + ind);
			printf("%08x, ", args[from++]);
			printf("\n");
			break;
		case _reg:
			printf("%s:%d\t\t", "reg", ins[i].args);
			from = ins[i].args;
			printf("%d, ", args[from++]);
			printf("%d, ", args[from++]);
			printf("\n");
			break;
		case _regn:
			printf("%s:%d\t\t", "regn", ins[i].args);
			from = ins[i].args;
			printf("%d, ", args[from++]);
			printf("%d, ", args[from++]);
			printf("\n");
			break;
			S(frt, 1);
			S(ans, 0);
			S(for,0);
			S(continue, 0);
			S(break, 0);
			S(if, 1);
			S(if_not, 1);
			S(loop, 3);
			S(cmd, 3);
			S(goto, 1);
			S(call, 0);
			S(return, 0);
			S(end, 0);
			S(cs, 0);
		default:
			break;
		}
#undef S
	}
	return 0;
}
#pragma region TestSuit
#if testSuit == 2
#include <stdio.h>
int _cmd_echo(int n, char *args[])
{
	for (int i = 0; i < n; i++)
	{
		printf("%s ", args[i]);
	}
	printf("\n");
	return 0;
}
static Any _test_args[] = {
	3,
	_cmd_echo,
	2,
	"hello",
	"world"};
/*
loop 3
	echo hello world
end

*/
static Li_Ins_t _test_asm[] = {
	{_loop, 0},
	{_cmd, 1},
	{_loop_return, 0},
	{_end, 0}};

int main()
{
	Li_CB_t cb;
	cb.pc = _test_asm;
	cb.lp = (LoopControlBlock)malloc(sizeof(*(cb.lp)) * 8);
	while (cb.pc)
	{
		_run_instruction(&cb, _test_args);
	}
	return 0;
}
#endif
#pragma endregion